package com.maybach.workflow.core.processor.impl;

import com.maybach.util.AssertUtil;
import com.maybach.workflow.common.api.WorkFlowContext;
import com.maybach.workflow.common.api.enums.TaskStateEnum;
import com.maybach.workflow.common.api.node.BaseNode;
import com.maybach.workflow.common.model.FlowDO;
import com.maybach.workflow.common.model.FlowTaskActorDO;
import com.maybach.workflow.common.model.FlowTaskDO;
import com.maybach.workflow.common.model.FlowTaskHisDO;
import com.maybach.workflow.core.expression.LogicalExprHelper;
import com.maybach.workflow.core.processor.IProcessor;
import com.maybach.workflow.core.processor.ProcessorFactory;
import com.maybach.workflow.core.repository.IFlowRepository;
import com.maybach.workflow.core.service.SecurityService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by houenxun on 15/8/13.
 */
public abstract class AbstractProcessor implements IProcessor {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    protected IFlowRepository flowRepository;
    @Autowired
    protected SecurityService securityService;

    @Autowired
    protected LogicalExprHelper logicalExprHelper;


    protected void logFlow(BaseNode nextNode, String desc, Long taskId) {
        /*FlowLogDO flowLogDO = new FlowLogDO();
        if (AudiUser.getUserName() != null && AudiUser.getUserName().getRoles() != null && AudiUser.getUserName().getRoles().length > 0) {
            flowLogDO.setActRole(AudiUser.getUserName().getRoles()[0]);
            flowLogDO.setUserId(AudiUser.getUserName().getUserId());
        }
        flowLogDO.setActType(nextNode.getNodeType().name());
        flowLogDO.setLogDesc(desc);
        flowLogDO.setTaskId(taskId);
        flowLogDAO.insert(flowLogDO);
*/
    }

    protected void logFlowTaskHis(FlowDO flowDO, FlowTaskDO flowTaskDO, FlowTaskActorDO taskActorDO) {
        if (flowTaskDO == null || null == flowDO) {
            return;
        }
        FlowTaskHisDO flowTaskHisDO = new FlowTaskHisDO();
        flowTaskHisDO.setTaskType(flowTaskDO.getTaskType());
        flowTaskHisDO.setTaskId(flowTaskDO.getId());
        flowTaskHisDO.setFlowId(flowTaskDO.getFlowId());
        flowTaskHisDO.setBizId(flowDO.getBizId());
        flowTaskHisDO.setBizType(flowDO.getBizType());
        flowTaskHisDO.setFlowName(flowDO.getFlowName());
        if (null != taskActorDO) {
            flowTaskHisDO.setActorType(taskActorDO.getActorType());
            flowTaskHisDO.setActorValue(taskActorDO.getValue());
        }
        flowTaskHisDO.setDisplayName(flowTaskDO.getDisplayName());
        flowTaskHisDO.setExecuteUserId(securityService.getUserId());
        flowTaskHisDO.setTaskName(flowTaskDO.getTaskName());
        flowTaskHisDO.setTaskState(TaskStateEnum.success.getStatus());
        flowTaskHisDO.setParentTaskId(flowTaskDO.getParentTaskId());
        flowTaskHisDO.setTaskCreateTime(flowTaskDO.getGmtCreate());

        flowRepository.createFlowTaskHis(flowTaskHisDO);
    }

    /*protected void refreshFragment(WorkFlowContext workFlowContext) {
        //流程片段改成支持排序 fixed by weishuai
        Collection<FlowChain> framentValues = FlowRunData.getFlowChainFactory().getFramentMapByName().values();
        List<FlowChain> framentFlowChainList = new ArrayList<FlowChain>(framentValues);
        Collections.sort(framentFlowChainList, new Comparator<FlowChain>() {

            @Override
            public int compare(FlowChain o1, FlowChain o2) {
                return o1.getOrder() - o2.getOrder();
            }
        });
        for (FlowChain f : framentFlowChainList) {
            if(logicalExprHelper.judgeFairily(f.getExpression(), workFlowContext.getBizData())){
                workFlowContext.setFragmentFlowChain(f);
                break;
            }
        }
        FlowDO flowDO = workFlowContext.getThisFlow();
        if (null != workFlowContext.getFragmentFlowChain() && !flowDO.getFlowName().equals(workFlowContext.getFragmentFlowChain().getName())) {
            flowRepository.updateFlowChain(workFlowContext.getThisFlow().getFlowId(), workFlowContext.getFragmentFlowChain().getName());
            flowDO.setFlowName(workFlowContext.getFragmentFlowChain().getName());
        }
    }*/


    /*protected void prepareContext(WorkFlowContext workFlowContext) {
        if (null == workFlowContext.getThisFlow()) {
            workFlowContext.setThisFlow(flowRepository.getFlowByBizIdAndType(workFlowContext.getBizId(), workFlowContext.getBizType()));
        }

        if (null == workFlowContext.getThisNode()) {
            workFlowContext.setThisNode(workFlowContext.getThisFlowChain().getMap().get(workFlowContext.getActionName()));
        }

    }*/

    protected BaseNode getNextNode(WorkFlowContext workFlowContext, BaseNode baseNode) {
        AssertUtil.notBlank(baseNode.getTo(), "baseNode.getTo()");
        return workFlowContext.getThisFlowChain().getMap().get(baseNode.getTo());
    }


    /**
     * 非存储结点流出逻辑
     *
     * @param workFlowContext
     */
    protected void noPersistRunOut(WorkFlowContext workFlowContext) {
        BaseNode thisNode = workFlowContext.getThisNode();
        this.logFlow(thisNode, "执行任务:[" + thisNode.getDisplayName() + "]", this.getThisTaskId(workFlowContext));
        BaseNode nextNode = this.getNextNode(workFlowContext, thisNode);
        workFlowContext.setThisNode(nextNode);
        ProcessorFactory.getProcessor(nextNode.getNodeType()).runIn(workFlowContext);
    }

    protected Long getThisTaskId(WorkFlowContext context) {
        return context.getThisTask() == null ? 0L : context.getThisTask().getId();
    }

    protected Long getParentTaskId(WorkFlowContext workFlowContext) {
        if (null != workFlowContext.getLastTask()) {
            return workFlowContext.getLastTask().getId();
        }
        return 0L;
    }

    protected List<BaseNode> getCommonNextNodes(WorkFlowContext workFlowContext) {
        BaseNode thisNode = workFlowContext.getThisNode();
        List<BaseNode> list = new ArrayList<BaseNode>();
        list.add(thisNode);
        BaseNode nextNode = this.getNextNode(workFlowContext, thisNode);
        workFlowContext.setThisNode(nextNode);
        list.addAll(ProcessorFactory.getProcessor(nextNode.getNodeType()).getNextNodes(workFlowContext));
        return list;
    }

}
